//******************************************************************
//******************************************************************
//**********          ANts Peer To Peer Sources        *************
//
// ANts P2P realizes a third generation P2P net. It protects your
// privacy while you are connected and makes you not trackable, hiding
// your identity (ip) and crypting everything you are sending/receiving
// from others.

// Copyright (C) 2004  Roberto Rossi

// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

package ants.p2p.messages.security;

import ants.p2p.*;

import java.security.*;
import java.security.spec.*;
import java.security.interfaces.*;
import java.beans.*;
import java.io.*;

public class MessageSigner {
  KeyPair pair;
  byte[] encodedPublic;
  static MessageSigner instance = null;

  public static final long []sizeLimits = {Long.MAX_VALUE, Long.MAX_VALUE, (long)Math.pow(2,10)*15};

  MessageSigner() throws Exception{
    long userSeed = System.currentTimeMillis();
    KeyPairGenerator keyGen = KeyPairGenerator.getInstance("DSA");
    SecureRandom random = SecureRandom.getInstance("SHA1PRNG", "SUN");
    random.setSeed(userSeed);
    keyGen.initialize(1024, random);
    pair = keyGen.generateKeyPair();
    encodedPublic = pair.getPublic().getEncoded();
  }

  public void sign(Message m) throws Exception{
    Message signable = m.getSignableMessage();
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    ObjectOutputStream oos = new ObjectOutputStream(baos);
    oos.writeObject(signable);
    oos.close();
    Signature dsa = Signature.getInstance("SHA1withDSA");
    dsa.initSign(pair.getPrivate());
    dsa.update(baos.toByteArray());
    m.setSignature(dsa.sign());
    m.setPublicKey(encodedPublic);
  }

  public static MessageSigner getInstance() throws Exception{
    if(instance == null)
      return instance = new MessageSigner();
    else
      return instance;
  }

  public String getPublicKey(){
    return ((DSAPublicKey)this.pair.getPublic()).getY().toString();
  }

  public boolean verifySignature(Message m, String Y) throws Exception{
    if(Y == null || Y.equals(""))
      return true;
    X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(m.getPublicKey());
    KeyFactory keyFact = KeyFactory.getInstance("DSA");
    DSAPublicKey pubk = (DSAPublicKey)keyFact.generatePublic(x509KeySpec);
    if(!pubk.getY().toString().equals(Y)){
      System.out.println("Source doesn't match:\n" + pubk.getY() + "\n" + Y);
      return false;
    }
    Signature dsa = Signature.getInstance("SHA1withDSA");
    dsa.initVerify(pubk);
    byte[] signature = m.getSignature();
    Message signable = m.getSignableMessage();
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    ObjectOutputStream oos = new ObjectOutputStream(baos);
    oos.writeObject(signable);
    oos.close();
    dsa.update(baos.toByteArray());
    return dsa.verify(signature);
  }

  public boolean verifySize(Message m) throws Exception{
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    ObjectOutputStream oos = new ObjectOutputStream(baos);
    oos.writeObject(m);
    oos.close();
    if(m.getType() < sizeLimits.length && baos.toByteArray().length <= sizeLimits[m.getType()]){
      return true;
    }else{
      return false;
    }
  }
}
